#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include "keycode.h"

static struct operate_handle keycode_handle;
static int group_switch(struct operate_handle * keycode_handle);

static char * sub_string(unsigned char * des, unsigned char * src, unsigned int len)
{
	char *tmp = des;

	while(len > 0 && len--) {
		*des++ = *src++;
	}

	return tmp;
}

int ret_monitor(unsigned char * buf, unsigned char * keycode, unsigned int len)
{
	if (len == 3)
		return atoi(sub_string(buf, keycode, 1));
	else if (len == 4)
		return atoi(sub_string(buf, keycode, 2));
	else if (len == 5) 
		return atoi(sub_string(buf, keycode, 3));	
}

int ret_value(unsigned char * buf, unsigned char * keycode, unsigned int len)
{
	if (len == 8)
		return atoi(sub_string(buf, keycode+5, 1));
	else if (len == 9)
		return atoi(sub_string(buf, keycode+5, 2));
	else if (len == 10) 
		return atoi(sub_string(buf, keycode+5, 3));
	else if (len == 11) 
		return atoi(sub_string(buf, keycode+5, 4));
}

/*
 * 处理收到的键盘数据
 */
int ProcessKey(unsigned  char * keycode)
{
	char buf[256];
	int len;
	
	if ( keycode == NULL) {
		perror("key code was null!\n");
		return -1;
	}
	
	memset(buf, 0, sizeof buf);	
	keycode_trace(LEVEL_2, "\t[[ %s ]]\n", keycode);
	len = strlen(keycode);
	keycode_trace(LEVEL_2, "length is [%d]", len);

	switch(keycode[len - 2]) {		
		case 'M':	/* 选择监视器 */
			keycode_handle.monitor_num = ret_monitor(buf, keycode, len);
			keycode_handle.action = KB_SELECT_MON ; 
			//printf("\t\t\t[monitor num = %d]\n", keycode_handle.monitor_num);
			break;
		
		case '#':	/* 选择摄像机 */
			keycode_handle.camera_num = ret_value(buf, keycode, len);
			keycode_handle.action = KB_SELECT_CAM  ; 
			//printf("\t\t\t[camrema num = %d]\n", keycode_handle.camera_num);
			break;		
		
		case '^':	/* 预置设置 */
			keycode_handle.shot_value = ret_value(buf, keycode, len);
			//printf("shot_set_value num = %d\n", keycode_handle.shot_value);
			keycode_handle.action = PTZ_SET_POINT;
			break;
		
		case '\\':	/* 预置调用 */
			keycode_handle.shot_value = ret_value(buf, keycode, len);
			//printf("shot_call_value num = %d\n", keycode_handle.shot_value);
			keycode_handle.action = PTZ_GOTO_POINT ;
			break;
		
		case 'K':	/* 锁定摄像机 */
			keycode_handle.action = KB_LOCK_PTZ ;
			break;
		
		case 'J':	/* 解锁摄像机 */
			keycode_handle.action = KB_UNLOCK_PTZ ;
			break;
		
		case 'S':	/* 按组号轮巡 */
			if (strlen(keycode) == 7)
				//继续正在运行的巡视
				keycode_handle.action = KB_RUN ;
			else
			{
				//开始一个新的巡视
				keycode_handle.run_val = ret_value(buf, keycode, len);
				keycode_handle.action = KB_RUN_GROUP ;
				//printf("\t\t\t[run_val num = %d]\n", keycode_handle.run_val);
			}		
			
			break;
		
		case 'H':	/* 暂停正在运行的巡视 */
			//keycode_handle.hold_val = ret_value(buf, keycode, len);
			keycode_handle.action = KB_HOLD ;			

			break;
			
		case '$':	/* 成组切换 */
			if (strlen(keycode) == 7)
				keycode_handle.salvo_val = keycode_handle.monitor_num;
			else
				keycode_handle.salvo_val = ret_value(buf, keycode, len);
			keycode_handle.action = KB_SALVO ;
			//printf("salvo_val num = %d\n", keycode_handle.salvo_val);
			break;		


		case 'U':	/* 向上 */
			if (strlen(keycode) == 7)
				keycode_handle.speed = 6;
			else
				keycode_handle.speed = atoi(sub_string(buf,keycode+5,1));

			//printf("speed num = %d\n", keycode_handle.speed);

			if (keycode_handle.speed > 0)
				keycode_handle.action = PTZ_UP_START;
			else if (keycode_handle.speed == 0)
				keycode_handle.action = PTZ_UP_STOP;
			break;	
			
		case 'D':	/* 向下 */
			if (strlen(keycode) == 7)
				keycode_handle.speed = 6;
			else
				keycode_handle.speed = atoi(sub_string(buf,keycode+5,1));

			//printf("speed num = %d\n", keycode_handle.speed);

			if (keycode_handle.speed > 0)
				keycode_handle.action = PTZ_DOWN_START;
			else
				keycode_handle.action = PTZ_DOWN_STOP;
			break;
		case 'L':	/* 向左 */
			if (strlen(keycode) == 7)
				keycode_handle.speed = 6;
			else
				keycode_handle.speed = atoi(sub_string(buf,keycode+5,1));

			//printf("speed num = %d\n", keycode_handle.speed);

			if (keycode_handle.speed > 0)
				keycode_handle.action = PTZ_LEFT_START;
			else
				keycode_handle.action = PTZ_LEFT_STOP;			
			break;
		case 'R':	/* 向右 */
			if (strlen(keycode) == 7)
				keycode_handle.speed = 6;
			else				
				keycode_handle.speed = atoi(sub_string(buf,keycode+5,1));

			//printf("speed num = %d\n", keycode_handle.speed);

			if (keycode_handle.speed > 0)
				keycode_handle.action = PTZ_RIGHT_START;
			else
				keycode_handle.action = PTZ_RIGHT_STOP;
			break;

		case 'O':	/* 光圈开 */
			keycode_handle.action = PTZ_IRIS_OPEN_START;
			break;
		case 'C':	/* 光圈关 */
			keycode_handle.action = PTZ_IRIS_CLOSE_START;
			break;

		case 'N':	/* 焦点近 */
			keycode_handle.action = PTZ_FOCUS_NEAR_START;
			break;
		case 'F':	/* 焦点远 */
			keycode_handle.action = PTZ_FOCUS_FAR_START;
			break;

		case 'W':	/* 焦距长 */
			keycode_handle.action = PTZ_ZOOM_WIDE_START;
			break;
		case 'T':	/* 焦距短 */
			keycode_handle.action = PTZ_ZOOM_TELE_START;
			break;

		default:
			break;
	}

	//检查是否要切换摄像机
	if (keycode_handle.action == KB_SELECT_CAM)
	{
		switch_camera(keycode_handle);
	}
	
	if ((keycode_handle.action == KB_RUN_GROUP) || (keycode_handle.action == KB_RUN) 
		|| (keycode_handle.action == KB_HOLD) || (keycode_handle.action == KB_EXIT_GROUP) ) 
	{
		//轮巡处理
		RunGroup(&keycode_handle) ;
		
	}
	else if ( (keycode_handle.action == KB_SALVO) )
	{
		//成组切换
		group_switch(&keycode_handle);
	}
	else
	{
		//云台控制
		PtzCtrl(keycode_handle);
	}

	return 0;
}

//初始化监视器轮巡数据
int monitor_run_init(void)
{
	int i;

	for(i=0;i<MAX_MONITORS;i++)
	{
		g_MonitorRun[i].MonitorNo = 0 ;
		g_MonitorRun[i].GroupNo = 0 ;		
		g_MonitorRun[i].eRunState = RUN_UNUSE ;			
		g_MonitorRun[i].tid_run = 0 ;
	}
	
	pthread_mutex_init(&g_RunMutex,NULL);
		
	return 0 ;
}

//退出监视器轮巡数据
static int monitor_run_exit(TMonitorRun *pRun)
{
	pthread_mutex_lock(&g_RunMutex) ;
	{
		pRun->eRunState = RUN_UNUSE ;
		
		void *ptr;
		pthread_join(pRun->tid_run, &ptr);
				
		pRun->MonitorNo = 0 ;
		pRun->GroupNo = 0 ;						
		pRun->tid_run = 0 ;
	}
	pthread_mutex_unlock(&g_RunMutex) ;
	
	
	return 0 ;
}

/*
 * 退出键盘所有线程
 */
int exit_thread_keyocde()
{
	int i;

	for (i = 0; i < MAX_MONITORS; i++) {
		if ( g_MonitorRun[i].eRunState != RUN_UNUSE)
			monitor_run_exit(&g_MonitorRun[i]);
	}
}

//轮巡处理
static int RunGroup(operate_handle * pOperVal) 
{
	int i,monitor_index1,isRuningIndex = 0;
	BOOL isRuning = FALSE ;
	
	for(i=0;i<MAX_MONITORS;i++)
	{	
		 //此监视器是否在轮巡		 
		 if (g_MonitorRun[i].MonitorNo == pOperVal->monitor_num && g_MonitorRun[i].eRunState != RUN_UNUSE)
		 {
		 	isRuning = TRUE ;
		 	isRuningIndex = i ;
		 	break ;
		 }	 		 
	}
	
	switch (pOperVal->action)
	{
		case KB_RUN_GROUP :  //按组号轮巡
		{
			if (isRuning)
			{
				//如果有相同的组在轮巡，则返回
				if (g_MonitorRun[isRuningIndex].GroupNo == pOperVal->run_val)
				{
					break ;
				}				
								
				//如果有另一分组在轮巡，则退出该轮巡
				if (g_MonitorRun[isRuningIndex].GroupNo != pOperVal->run_val)
				{
					monitor_run_exit(&g_MonitorRun[isRuningIndex]) ;
					
				}
			}
			
			//查找可用的轮巡状态号
			for(isRuningIndex=0;i<MAX_MONITORS;isRuningIndex++)
			{	
				 //此监视器是否在轮巡		 
				 if (g_MonitorRun[isRuningIndex].eRunState == RUN_UNUSE)
				 {			
				 	break ;
				 }				 
			}			
			
			if (isRuningIndex < MAX_MONITORS)
			{	
				//pthread_mutex_lock(&g_RunMutex) ;					
				g_MonitorRun[isRuningIndex].MonitorNo =  pOperVal->monitor_num ;
				g_MonitorRun[isRuningIndex].GroupNo =  pOperVal->run_val ;
				//pthread_mutex_unlock(&g_RunMutex) ;
				 
				pthread_create(&g_MonitorRun[isRuningIndex].tid_run, NULL, RunGroup_Thread, &g_MonitorRun[isRuningIndex]);
			}
			
			break ;
		}

		case KB_HOLD :  //暂停正在运行的巡视
		{
			if (isRuning )
			{
				 pthread_mutex_lock(&g_RunMutex) ;
				 g_MonitorRun[isRuningIndex].eRunState = RUN_HOLD ;
				 pthread_mutex_unlock(&g_RunMutex) ;
			}
		
			break ;
		}

		case KB_RUN :  //继续正在运行的巡视
		{
			if (isRuning)
			{
				pthread_mutex_lock(&g_RunMutex) ;
				g_MonitorRun[isRuningIndex].eRunState = RUN_RUNNING ;
				pthread_mutex_unlock(&g_RunMutex) ;
			}		
			break ;
		}	
			
		case KB_EXIT_GROUP :  //退出正在运行的巡视
		{
			if (isRuning)
			{
				monitor_run_exit(&g_MonitorRun[isRuningIndex]) ;
			}		
			break ;
		}		
	}	
}

//按组号轮巡的线程
static void *RunGroup_Thread(void * pParam)
{
	TDeviceInfo	*pmonitor, *pcamera;
	TMonitorRun * pRun = (TMonitorRun *)pParam;
	TReqPtzAct ptzact;
	enPtzAction action;
	
	grouplist *head, *newnode, *posnode;  //存储摄像机分组数据的双向链表
	struct list_head *pos;
	int times = 0 ; 
			
	//pthread_detach(pthread_self()) ;	
	
	//取pRun->MonitorNo 对应的解码器参数
	pmonitor = search(pRun->MonitorNo, MONITOR);	
	if (pmonitor == NULL)
	{
		pthread_exit(NULL) ;
	}	
	
	//取pRun->GroupNo 对应的编码器参数
	NEW_LIST_NODE(grouplist, head);
	INIT_LIST_HEAD(&head->list);
	int group_items = get_signle_group(head, newnode, pRun->GroupNo) ;	
	if (group_items < 1)
	{
		// 释放存取数据的双链表
		FREE_LIST(grouplist, head, list);
		pthread_exit(NULL) ;		
	}
	
	printf("***************************PID: %d --->RunGroup_Thread()\n", getpid());
	
	pRun->eRunState = RUN_RUNNING;	
	while(pRun->eRunState != RUN_UNUSE)
	{

		//循环读取摄像机分组数据
		list_for_each(pos, &(head->list)) 
		{
			posnode = list_entry(pos, grouplist, list);
			//printf("\t[%s:%d\tgrouplist]\n", __FUNCTION__,__LINE__);
			//print_result(posnode);
		
			pcamera = search(posnode->group.CameraNo, CAMERA);
			//printf("\t[%s:%d\tcamera]\n", __FUNCTION__,__LINE__);
			//print_device_info(pcamera);
			
			if (pcamera) 
			{
				// 切换
				SwitchCamera(pmonitor, pcamera);
				
				// 预置调用
				if (posnode->group.PresetNo > 0) 
				{
					action = PTZ_GOTO_POINT;
					ptzact.ActParam.Param1 = posnode->group.PresetNo;
					PtzControl(pcamera->IP, pcamera->Port, pcamera->ChanNum, action, ptzact.ActParam);
				}
				
				//停留时间的处理
				times = 0 ;
				while ( (times < posnode->group.StopTime) )
				{
					sleep(1) ;
					if (pRun->eRunState == RUN_RUNNING)
						times++ ;
					else if (pRun->eRunState == RUN_UNUSE)
						break ;				
				}
				
				if (pRun->eRunState == RUN_UNUSE)
					break ;
				
			}
			else {
				// 释放存取数据的双链表
				FREE_LIST(grouplist, head, list);
				pthread_exit(NULL) ;		
				//return ;
			}
		}//list_for_each(pos, &(head->list))
				
	}//(pRun->eRunState != RUN_UNUSE)	
	
	// 释放存取数据的双链表
	FREE_LIST(grouplist, head, list);
	
	printf("*************************** Exit RunGroup_Thread()...,PID= %d \n", getpid());
	
	pthread_exit(NULL) ;
	
}
		
/*
 * 切换摄像机
 */
static int switch_camera(operate_handle keycode_handle)
{
	TDeviceInfo	*pmonitor, *pcamera;	
	enPtzAction action ;
	
	// 寻找监视器与摄像头.
	if ((keycode_handle.monitor_num > 0 && keycode_handle.camera_num > 0)) {
		
		//如果此监视器正在轮巡,则退出此轮巡
		action = keycode_handle.action ;
		keycode_handle.action = KB_EXIT_GROUP ;
		RunGroup(&keycode_handle) ;
		keycode_handle.action = action ;
		
		//取解码器的参数，取编码器的参数
		pmonitor = search(keycode_handle.monitor_num, MONITOR);
		pcamera = search(keycode_handle.camera_num, CAMERA);
		//print_device_info(pcamera);
		//print_device_info(pmonitor);
		
		// 切换
		if (pmonitor && pcamera) 
			SwitchCamera(pmonitor, pcamera);
		else
			return -1;
	}

	return 0;
}

/*
 * 云台控制,预置设置,预置调用
 */
static int PtzCtrl(operate_handle keycode_handle)
{
	TReqPtzAct ptzact;
	TDeviceInfo	*pcamera;

	keycode_trace(LEVEL_2, "\t[[ camera_num	= %d ]]\n", keycode_handle.camera_num);
	keycode_trace(LEVEL_2, "\t[[ speed		= %d ]]\n", keycode_handle.speed);

	if (keycode_handle.camera_num > 0) {
		pcamera = search(keycode_handle.camera_num, CAMERA);
		//print_device_info(pcamera);

		if (pcamera) {
			ptzact.ActParam.Param1 = keycode_handle.speed;

			if  ((keycode_handle.action == PTZ_SET_POINT || 
				keycode_handle.action == PTZ_GOTO_POINT) && 
				keycode_handle.shot_value > 0)
					ptzact.ActParam.Param1 = keycode_handle.shot_value;
			
			PtzControl(pcamera->IP, pcamera->Port, pcamera->ChanNum, keycode_handle.action, ptzact.ActParam);
			
		}
		else// 没找到相应camera.
			return -1;
	}
	else	// 没有摄像机编号
		return -2;

	return 0;
}

static int group_switch(struct operate_handle * keycode_handle)
{
	TDeviceInfo	monitor[MONITOR_COUNT];
	//TDeviceInfo	camera[CAMERA_COUNT], temp;
	TDeviceInfo *pmonitor, *pcamera;
	unsigned int monitor_all_count = 0;	/* 监视器总数 */
	unsigned int i, monitor_position;	/* 目标监视器排列位置 */
	grouplist **group_ret;	/* 轮巡组数据 */
	int camera_count;		/* 要换切的摄像机数 */
	operate_handle handle;

	if (keycode_handle->monitor_num < 0) {
		return -1;
	}

	//printf("------- salvo ------\n");
	// 存取所有监视器
	memset(monitor, 0, sizeof monitor);
	monitor_all_count = get_device_param(MON_FILE, monitor);
	//printf("------- monitor_all_count:%d ------\n", monitor_all_count);
	
	// 确定摄像头数
	camera_count = 0;
	group_ret = group_item(keycode_handle->salvo_val, &camera_count);
	if (camera_count == 0)
		return -1;

	// 确定目标监视器
	monitor_position = 0;
	pmonitor = monitor;
	for (monitor_position = 0; monitor_position < monitor_all_count; monitor_position++, pmonitor++) {
		if (pmonitor->DeviceNo == keycode_handle->monitor_num) {
			for (i = 0; i < camera_count; i++) {
				// 查找摄像头
				pcamera = search(group_ret[i]->group.CameraNo, CAMERA);
				//printf("\t[%s:%d\tcamera]\n", __FUNCTION__,__LINE__);
				//print_device_info(pcamera);

				if (monitor[monitor_position + i].DeviceNo && pcamera) {

					handle.monitor_num = monitor[i].DeviceNo;
					handle.action  = KB_EXIT_GROUP;
					RunGroup(&handle) ;

					SwitchCamera(&monitor[monitor_position+i], pcamera);
				}
					
				if ( monitor_position + i > monitor_all_count) {
					free(group_ret);
					return 0;
				}
			}
			if (i == camera_count) {
				free(group_ret);
				return ;
			}
		}
	}
	free(group_ret);

	return 0;
}

